package com.ldk.base.framework.datasource.generator;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.util.List;
import java.util.Random;

/**
 * EntityGenerator 实体生成器基类
 * @author mqy
 *
 */
public abstract class EntityGenerator {

	/**
	 * 基类实体类
	 */
	private final String BaseEntityClassName = "com.ldk.base.framework.entity.BaseEntity";
	/**
	 * 基类DAO接口类
	 */
	private final String IBaseDAOClassName = "com.ldk.base.framework.dao.IBaseDAO";
	/**
	 * 基类DAO实现类
	 */
	private final String BaseDAOClassName = "com.ldk.base.framework.dao.impl.BaseDAO";
	/**
	 * 基类Service接口类
	 */
	private final String IBaseServiceClassName = "com.ldk.base.framework.service.IBaseService";
	/**
	 * 基类Service实现类
	 */
	private final String BaseServiceClassName = "com.ldk.base.framework.service.impl.BaseService";

	private String serverName;
	private int    portNumber;
	private String databaseName;
	private String user;
	private String password;

	public String getServerName() {
		return serverName;
	}
	public int getPortNumber() {
		return portNumber;
	}
	public String getDatabaseName() {
		return databaseName;
	}
	public String getUser() {
		return user;
	}
	public String getPassword() {
		return password;
	}
	public void setServerName(String serverName) {
		this.serverName = serverName;
	}
	public void setPortNumber(int portNumber) {
		this.portNumber = portNumber;
	}
	public void setDatabaseName(String databaseName) {
		this.databaseName = databaseName;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * 日志器
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 数据库类型
	 * @return
	 */
	protected abstract DBType getDbType();

	/**
	 * 获取表
	 * @return
	 */
	protected abstract List<String> getTables();

	/**
	 * 获取表字段
	 * @return
	 */
	protected abstract List<TableColumn> getTableColums(String table);

	/**
	 * 根据表字段类型获取对应的列数据类型
	 * @param dataType
	 * @return
	 */
	protected TableColumnDataType getColumnDataType(String dataType) {
		if(dataType.equalsIgnoreCase(TableColumnDataType.BIGINT.getSqlType())){
			return TableColumnDataType.BIGINT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.BINARY.getSqlType())){
			return  TableColumnDataType.BINARY;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.BIT.getSqlType())){
			return  TableColumnDataType.BIT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.BLOB.getSqlType())){
			return  TableColumnDataType.BLOB;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.BOOLEAN.getSqlType())){
			return  TableColumnDataType.BOOLEAN;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.CHAR.getSqlType())){
			return  TableColumnDataType.CHAR;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.CLOB.getSqlType())){
			return  TableColumnDataType.CLOB;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.DATE.getSqlType())){
			return  TableColumnDataType.DATE;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.DECIMAL.getSqlType())){
			return  TableColumnDataType.DECIMAL;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.DOUBLE.getSqlType())){
			return  TableColumnDataType.DOUBLE;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.FLOAT.getSqlType())){
			return  TableColumnDataType.FLOAT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.INTEGER.getSqlType())){
			return  TableColumnDataType.INTEGER;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.JSON.getSqlType())){
			return  TableColumnDataType.JSON;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.LONGVARBINARY.getSqlType())){
			return  TableColumnDataType.LONGVARBINARY;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.LONGVARCHAR.getSqlType())){
			return  TableColumnDataType.LONGVARCHAR;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NCHAR.getSqlType())){
			return  TableColumnDataType.NCHAR;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NCLOB.getSqlType())){
			return  TableColumnDataType.NCLOB;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NULL.getSqlType())){
			return  TableColumnDataType.NULL;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NUMERIC.getSqlType())){
			return  TableColumnDataType.NUMERIC;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NVARCHAR.getSqlType())){
			return  TableColumnDataType.NVARCHAR;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.NVARCHAR2.getSqlType())){
			return TableColumnDataType.NVARCHAR2;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.OTHER.getSqlType())){
			return  TableColumnDataType.OTHER;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.REAL.getSqlType())){
			return  TableColumnDataType.REAL;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.SMALLINT.getSqlType())){
			return  TableColumnDataType.SMALLINT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.TEXT.getSqlType())){
			return  TableColumnDataType.TEXT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.TIME.getSqlType())){
			return  TableColumnDataType.TIME;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.TIMESTAMP.getSqlType())){
			return  TableColumnDataType.TIMESTAMP;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.TINYINT.getSqlType())){
			return  TableColumnDataType.TINYINT;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.VARBINARY.getSqlType())){
			return  TableColumnDataType.VARBINARY;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.VARCHAR.getSqlType())){
			return  TableColumnDataType.VARCHAR;
		}
		else if(dataType.equalsIgnoreCase(TableColumnDataType.VARCHAR2.getSqlType())){
			return  TableColumnDataType.VARCHAR2;
		}
		else{
			return TableColumnDataType.OTHER;
		}
	}

	/**
	 * 获取数据库连接
	 * @return
	 */
	protected abstract Connection getConnection();

	/**
	 * 构建
	 * @param folder 存放文件夹 如：D:/test
	 * @param basePackageName 基础包名 如:com.sunny.test
	 * @param clearPrefix 是否去除表名前缀，表名前缀为数据库名称 如:mss_
	 */
	public void build(String folder, String basePackageName, String clearPrefix){
		//获取数据库所有表
		List<String> tables = getTables();
		build(tables, folder, basePackageName, clearPrefix);
	}

	/**
	 * 构建
	 * @param tables 数据库表名列表
	 * @param folder 存放文件夹 如：D:/test
	 * @param basePackageName 基础包名 如:com.sunny.test
	 * @param clearPrefix 是否去除表名前缀，表名前缀为数据库名称 如:mss_
	 */
	public void build(List<String> tables, String folder, String basePackageName, String clearPrefix){
		//创建文件夹
		if(StringUtils.isBlank(folder)) return;
		if(!folder.endsWith("/")){
			folder += "/";
		}
		Boolean successed = createDir(folder);
		if(!successed) return;
		if(tables == null || tables.isEmpty()) return;
		for (String table : tables) {
			//根据表获取所有字段
			List<TableColumn> columns = getTableColums(table);
			if(columns == null || columns.isEmpty()) continue;
			String noPrefixTable = table;
			//是否清除前缀
			if(!StringUtils.isEmpty(clearPrefix)){
				noPrefixTable = table.replace(clearPrefix, "");
			}
			String className = firstLetterToUpper(underlineToCamel(noPrefixTable));
			//创建实体文件
			buildEntity(folder, basePackageName, className, columns);
			//创建DAO接口文件
			buildIDAO(folder, basePackageName, className, columns);
			//创建DAO实现文件
			buildDAO(folder, basePackageName, className, columns);
			//创建Service接口文件
			buildIService(folder, basePackageName, className, columns);
			//创建Service实现文件
			buildService(folder, basePackageName, className, columns);
			//创建Mapper文件
			buildMapper(folder, basePackageName, className, table, columns);
		}
	}
	/**
	 * 构建Entity的java文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param columns
	 */
	private void buildEntity(String folder,String basePackageName, String className, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/entity/%s.java", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String packageName = String.format("%s.entity", basePackageName);
		try{
			bw.write(String.format("package %s;",packageName));
			bw.newLine();
			bw.newLine();
			//创建引入包部分
			bw.write(String.format("import %s;\n", BaseEntityClassName));
			bw.newLine();
			//创建注释
			bw.write("/**");
			bw.newLine();
			bw.write(String.format("* %s实体类", className));
			bw.newLine();
			bw.write(String.format("* @author %s", "mqy"));
			bw.newLine();
			bw.write("*/");
			bw.newLine();
			//创建类
			bw.write(String.format("public class %s extends BaseEntity {", className));
			bw.newLine();
			bw.newLine();
			//创建属性
			//1、创建serialVersionUID
			Random r=new Random();
			bw.write("	private static final long serialVersionUID = " + String.valueOf(r.nextLong()) +"L;");
			bw.newLine();
			//2、创建private property
			for (TableColumn item : columns) {
				bw.write("	/**");
				bw.newLine();
				bw.write(String.format("	* %s", item.getComment()));
				bw.newLine();
				bw.write("	*/");
				bw.newLine();
				bw.write(String.format("	private %s   %s;", item.getDataType().getJavaType(), item.getPropertyName()));
				bw.newLine();
			}
			bw.newLine();
			//3、创建property的setter和getter
			for (TableColumn item : columns) {
				//getter
				String variable = item.getPropertyName();
				String property = firstLetterToUpper(variable);
				bw.write(String.format("	public %s get%s() {",
						item.getDataType().getJavaType(),
						property ));
				bw.newLine();
				bw.write(String.format("		return %s;", variable));
				bw.newLine();
				bw.write("	}");
				bw.newLine();
				//setter
				bw.write(String.format("	public void set%s (%s %s){", property, item.getDataType().getJavaType(), variable));
				bw.newLine();
				bw.write(String.format("    	this.%s = %s;",variable, variable));
				bw.newLine();
				bw.write("	}");
				bw.newLine();
			}
			bw.newLine();
			//创建结尾
			bw.write("}");
			bw.newLine();

			bw.flush();
			bw.close();
		}
		catch(Exception e){
			logger.error("build.Entity.Exception="+e.getMessage());
		}
	}
	/**
	 * 构建IDAO的java文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param columns
	 */
	private void buildIDAO(String folder,String basePackageName, String className, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/dao/I%sDAO.java", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String packageName = String.format("%s.dao", basePackageName);
		try{
			bw.write(String.format("package %s;",packageName));
			bw.newLine();
			bw.newLine();
			//创建引入包部分
			bw.write(String.format("import %s;",IBaseDAOClassName));
			bw.newLine();
			bw.write(String.format("import %s.entity.%s;",basePackageName, className));
			bw.newLine();
			//创建注释
			bw.write("/**");
			bw.newLine();
			bw.write(String.format("* %sDAO接口类", className));
			bw.newLine();
			bw.write(String.format("* @author %s", "mqy"));
			bw.newLine();
			bw.write("*/");
			bw.newLine();
			//创建接口
			bw.write(String.format("public interface I%sDAO extends IBaseDAO<%s> {", className, className));
			bw.newLine();
			bw.newLine();

			//创建尾部
			bw.write("}");
			bw.newLine();

			bw.flush();
			bw.close();
		}
		catch(Exception e){
			logger.error("build.IDAO.Exception="+e.getMessage());
		}
	}
	/**
	 * 构建DAO的java文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param columns
	 */
	private void buildDAO(String folder,String basePackageName,String className, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/dao/impl/%sDAO.java", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String packageName = String.format("%s.dao.impl", basePackageName);
		try{
			bw.write(String.format("package %s;",packageName));
			bw.newLine();
			bw.newLine();
			//创建引入包部分
			bw.write(String.format("import org.springframework.stereotype.Repository;"));
			bw.newLine();
			bw.write(String.format("import %s;", BaseDAOClassName));
			bw.newLine();
			bw.write(String.format("import %s.dao.I%sDAO;",basePackageName, className));
			bw.newLine();
			bw.write(String.format("import %s.entity.%s;",basePackageName, className));
			bw.newLine();
			bw.newLine();
			//创建注释
			bw.write("/**");
			bw.newLine();
			bw.write(String.format("* %sDAO接口实现类", className));
			bw.newLine();
			bw.write(String.format("* @author %s", "mqy"));
			bw.newLine();
			bw.write("*/");
			bw.newLine();
			//创建类
			bw.write("@Repository");
			bw.newLine();
			bw.write(String.format("public class %sDAO extends BaseDAO<%s> implements I%sDAO {", className, className, className));
			bw.newLine();
			bw.newLine();

			//创建尾部
			bw.write("}");
			bw.newLine();

			bw.flush();
			bw.close();
		}
		catch(Exception e){
			logger.error("build.Dao.Exception="+e.getMessage());
		}
	}
	/**
	 * 构建IService的java文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param columns
	 */
	private void buildIService(String folder,String basePackageName,String className, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/service/I%sService.java", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String packageName = String.format("%s.service", basePackageName);
		try{
			bw.write(String.format("package %s;",packageName));
			bw.newLine();
			bw.newLine();
			//创建引入包部分
			bw.write(String.format("import %s;", IBaseServiceClassName));
			bw.newLine();
			bw.write(String.format("import %s.entity.%s;",basePackageName, className));
			bw.newLine();
			bw.newLine();
			//创建注释
			bw.write("/**");
			bw.newLine();
			bw.write(String.format("* %sService接口类", className));
			bw.newLine();
			bw.write(String.format("* @author %s", "mqy"));
			bw.newLine();
			bw.write("*/");
			bw.newLine();
			//创建接口
			bw.write(String.format("public interface I%sService extends IBaseService<%s> {", className, className));
			bw.newLine();
			bw.newLine();

			//创建尾部
			bw.write("}");
			bw.newLine();

			bw.flush();
			bw.close();
		}
		catch(Exception e){
			logger.error("build.IService.Exception="+e.getMessage());
		}
	}
	/**
	 * 构建Service的java文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param columns
	 */
	private void buildService(String folder,String basePackageName,String className, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/service/impl/%sService.java", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String packageName = String.format("%s.service.impl", basePackageName);
		try{
			bw.write(String.format("package %s;",packageName));
			bw.newLine();
			bw.newLine();
			//创建引入包部分
			bw.write(String.format("import org.springframework.beans.factory.annotation.Autowired;"));
			bw.newLine();
			bw.write(String.format("import org.springframework.stereotype.Service;"));
			bw.newLine();
			bw.newLine();
			bw.write(String.format("import %s;", BaseServiceClassName));
			bw.newLine();
			bw.write(String.format("import %s;",IBaseDAOClassName));
			bw.newLine();
			bw.write(String.format("import %s.service.I%sService;",basePackageName,className));
			bw.newLine();
			bw.write(String.format("import %s.dao.I%sDAO;",basePackageName, className));
			bw.newLine();
			bw.write(String.format("import %s.entity.%s;",basePackageName, className));
			bw.newLine();
			bw.newLine();
			//创建注释
			bw.write("/**");
			bw.newLine();
			bw.write(String.format("* %sService接口实现类", className));
			bw.newLine();
			bw.write(String.format("* @author %s", "mqy"));
			bw.newLine();
			bw.write("*/");
			bw.newLine();
			//创建类
			bw.write("@Service");
			bw.newLine();
			bw.write(String.format("public class %sService extends BaseService<%s> implements I%sService {", className, className, className));
			bw.newLine();
			bw.newLine();
			//创建基类方法
			String variable = String.format("%sDAO", firstLetterToLower(className));
			bw.write("	@Autowired");
			bw.newLine();
			bw.write(String.format("	private I%sDAO %s;",className, variable));
			bw.newLine();
			bw.newLine();

			bw.write("	@Override");
			bw.newLine();
			bw.write(String.format("	protected IBaseDAO<%s> getBaseDao() {", className));
			bw.newLine();
			bw.write(String.format("     	return this.%s;", variable));
			bw.newLine();
			bw.write("	}");
			bw.newLine();
			//创建尾部
			bw.newLine();
			bw.write("}");
			bw.newLine();

			bw.flush();
			bw.close();
		}
		catch(Exception e){
			logger.error("build.Service.Exception="+e.getMessage());
		}
	}
	/**
	 * 构建Mapper的xml文件
	 * @param folder 根文件夹
	 * @param basePackageName
	 * @param className 类名称（表名转化后的名称）
	 * @param table 表名称
	 * @param columns
	 */
	private void buildMapper(String folder,String basePackageName,String className, String table, List<TableColumn> columns){
		if(StringUtils.isBlank(basePackageName) || StringUtils.isBlank(className))
			return;
		if(columns == null || columns.isEmpty())
			return;
		String fileName = String.format("%s/mapper/%sMapper.xml", folder, className);
		BufferedWriter bw = getBufferedWriter(fileName);
		if(bw == null) return;
		String daoPackageName = String.format("%s.dao.impl.%sDAO", basePackageName, className);
		String entityPackageName = String.format("%s.entity.%s", basePackageName, className);
		TableColumn keyColumn = null;
		for (TableColumn item : columns) {
			if(item.getIsKey()){
				keyColumn = item;
				break;
			}
		}
		if(keyColumn == null){
			keyColumn = columns.get(0);
		}
		try{
			bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			bw.newLine();
			bw.write("<!DOCTYPE mapper  PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
			bw.newLine();
			bw.write(String.format("<mapper namespace=\"%s\">", daoPackageName));
			bw.newLine();
			//resultMap start
			bw.write("	<!--ENTITY MAPPER-->");
			bw.newLine();
			bw.write(String.format("	<resultMap id=\"resultMap\" type=\"%s\">", entityPackageName));
			bw.newLine();
			//resultMap columns
			for (TableColumn item : columns) {
				// 注释
				bw.write(String.format("		<!-- %s -->", item.getComment()));
				bw.newLine();
				//
				bw.write(String.format("		<result column=\"%s\" property=\"%s\" />", item.getColumnName(), item.getPropertyName()));
				bw.newLine();
			}
			//resultMap end
			bw.write("	</resultMap>");
			bw.newLine();
			//where
			bw.newLine();
			bw.write("	<!-- WHERE -->");
			bw.newLine();
			bw.write("	<sql id=\"where\">");
			bw.newLine();
			bw.write("		<where>");
			bw.newLine();
			bw.write("       	<trim prefixOverrides=\"and\">");
			bw.newLine();
			for (TableColumn item : columns) {
				// boolean
				if (item.getDataType() == TableColumnDataType.BIT
						|| item.getDataType() == TableColumnDataType.BOOLEAN
						|| item.getDataType() == TableColumnDataType.TINYINT) {
					bw.write(String.format(
							"				<if test=\"%s != null \">and %s=#{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// int
				else if (item.getDataType() == TableColumnDataType.SMALLINT) {
					bw.write(String
							.format("				<if test=\"%s != null and %s > 0 \">and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();
				}// long
				else if (item.getDataType() == TableColumnDataType.INTEGER
						|| item.getDataType() == TableColumnDataType.BIGINT) {
					bw.write(String
							.format("				<if test=\"%s != null and %s > 0 \">and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();

				}// double
				else if (item.getDataType() == TableColumnDataType.DOUBLE
						|| item.getDataType() == TableColumnDataType.FLOAT) {
					bw.write(String
							.format("				<if test=\"%s != null and %s > 0 \">and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();

				}// float
				else if (item.getDataType() == TableColumnDataType.REAL) {
					bw.write(String
							.format("				<if test=\"%s != null and %s > 0 \">and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();

				}// byte[]
				else if (item.getDataType() == TableColumnDataType.BINARY
						|| item.getDataType() == TableColumnDataType.VARBINARY
						|| item.getDataType() == TableColumnDataType.LONGVARBINARY
						|| item.getDataType() == TableColumnDataType.BLOB) {
					bw.write(String.format(
							"					<if test=\"%s != null \">and %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// BigDecimal
				else if (item.getDataType() == TableColumnDataType.NUMERIC
						|| item.getDataType() == TableColumnDataType.DECIMAL) {
					bw.write(String
							.format("				<if test=\"%s != null and %s > 0 \">and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();

				}// Date
				else if (item.getDataType() == TableColumnDataType.DATE) {
					bw.write(String.format(
							"				<if test=\"%s != null \">and %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// time
				else if (item.getDataType() == TableColumnDataType.TIME) {
					bw.write(String.format(
							"				<if test=\"%s != null \">and %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// Timestamp
				else if (item.getDataType() == TableColumnDataType.TIMESTAMP) {
					bw.write(String.format(
							"				<if test=\"%s != null \">and %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// Object
				else if (item.getDataType() == TableColumnDataType.OTHER
						|| item.getDataType() == TableColumnDataType.NULL) {
					bw.write(String.format(
							"				<if test=\"%s != null \">and %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));
					bw.newLine();

				}// String
				else {
					bw.write(String
							.format("				<if test=\"%s != null and %s != '' \"> and %s = #{%s}</if>",
									item.getPropertyName(),
									item.getPropertyName(),
									item.getColumnName(),
									item.getPropertyName()));
					bw.newLine();
				}
			}
			//where end
			bw.write("       	</trim>");
			bw.newLine();
			bw.write("		</where>");
			bw.newLine();
			bw.write("	</sql>");
			bw.newLine();
			//order by
			bw.write("	<!---OEDER BY-->");
			bw.newLine();
			bw.write("	<sql id=\"order_by\">");
			bw.newLine();
			bw.write("			<if test=\"sorting != null and sorting != ''\">order by ${sorting}</if>");
			bw.newLine();
			bw.write("	</sql>");
			bw.newLine();
			DBType dbType = getDbType();
			//limit
			buildMapperLimit(dbType, bw, keyColumn);
			//select
			buildMapperSelect(dbType, bw, table, columns);
			//insert
			buildMapperInsert(bw, table, columns, entityPackageName);
			//update
			buildMapperUpdate(bw, table, columns);
			//delete
			buildMapperDelete(bw, table, keyColumn);
			//结束
			bw.write("</mapper>");

			bw.flush();
			bw.close();

		}catch(Exception e){
			logger.error("buildMapper.Mapper.Exception="+e.getMessage());
		}
	}
	/**
	 * buildMapperLimit
	 * @param dbType
	 * @param bw
	 * @param column
	 */
	private void buildMapperLimit(DBType dbType, BufferedWriter bw, TableColumn column){
		try{
			bw.write("	<!-- LIMIT -->");
			bw.newLine();
			if(dbType == DBType.ORACLE){
				bw.write("	<sql id=\"limit_header\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			select * from (");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
				bw.write("	<sql id=\"limit_rownumber\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			ROWNUM AS row_index,");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
				bw.write("	<sql id=\"limit_footer\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			) p");
				bw.newLine();
				bw.write("			where p.row_index >= (#{offset}) and (#{offset} + #{limit}) >= p.row_index");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
			}
			else if(dbType == DBType.MSSQL || dbType == DBType.DB2){
				bw.write("	<sql id=\"limit_header\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			select * from (");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
				bw.write("	<sql id=\"limit_rownumber\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			ROW_NUMBER() OVER(ORDER BY "+column.getColumnName()+") as row_index,");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
				bw.write("	<sql id=\"limit_footer\">");
				bw.newLine();
				bw.write("		<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			) p");
				bw.newLine();
				bw.write("			where p.row_index >= (#{offset}) and (#{offset} + #{limit}) >= p.row_index");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
			}
			else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
				bw.write("	<sql id=\"limit\">");
				bw.newLine();
				bw.write("	 	<if test=\"offset != null and limit != null\">");
				bw.newLine();
				bw.write("			limit #{offset},#{limit}");
				bw.newLine();
				bw.write("		</if>");
				bw.newLine();
				bw.write("	</sql>");
				bw.newLine();
			}
			bw.newLine();
		}
		catch(Exception e){
			logger.error("buildMapper.Limit.Exception="+e.getMessage());
		}

	}

	/**
	 * buildMapperSelect
	 * @param dbType
	 * @param bw
	 * @param table
	 * @param columns
	 */
	private void buildMapperSelect(DBType dbType, BufferedWriter bw, String table, List<TableColumn> columns){
		try{
			TableColumn keyColumn = null;
			for (TableColumn item : columns) {
				if(item.getIsKey()){
					keyColumn = item;
					break;
				}
			}
			if(keyColumn != null){
				//getMaxId
				bw.write("	<!-- getMaxId -->");
				bw.newLine();
				bw.write("	<select id=\"getMaxId\" parameterType=\"java.util.Map\" resultType=\"java.lang.Long\">");
				bw.newLine();
				bw.write(String.format("		select max(%s) from %s", keyColumn.getColumnName(), table));
				bw.newLine();
				bw.write("	</select>");
				bw.newLine();
				//selectByKey
				bw.write("	<!-- selectByKey -->");
				bw.newLine();
				bw.write("	<select id=\"selectByKey\" parameterType=\"java.util.Map\" resultMap=\"resultMap\">");
				bw.newLine();
				if(dbType == DBType.MSSQL || dbType == DBType.DB2){
					bw.write(String.format("		select top 1 * from %s where %s=#{%s}", table, keyColumn.getColumnName(), keyColumn.getPropertyName()));
				}
				else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
					bw.write(String.format("		select * from %s where %s=#{%s} limit 1", table, keyColumn.getColumnName(), keyColumn.getPropertyName(), keyColumn.getPropertyName()));
				}
				else if(dbType == DBType.ORACLE){
					bw.write(String.format("		select * from (select  * from %s where %s=#{%s}) where ROWNUM = 1", table, keyColumn.getColumnName(), keyColumn.getPropertyName()));
				}
				else{
					bw.write(String.format("		select * from %s where %s=#{%s}", table, keyColumn.getColumnName(), keyColumn.getPropertyName()));
				}
				bw.newLine();
				bw.write("	</select>");
				bw.newLine();
				//selectCount
				bw.write("	<!-- selectCount -->");
				bw.newLine();
				bw.write("	<select id=\"selectCount\" parameterType=\"java.util.Map\" resultType=\"java.lang.Long\">");
				bw.newLine();
				bw.write(String.format("		select count(%s) from %s",keyColumn.getColumnName() , table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("	</select>");
				bw.newLine();
			}
			//selectOne
			bw.write("	<!-- selectOne -->");
			bw.newLine();
			bw.write("	<select id=\"selectOne\" parameterType=\"java.util.Map\" resultMap=\"resultMap\">");
			bw.newLine();
			if(dbType == DBType.MSSQL){
				bw.write(String.format("		select top 1 * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.ORACLE){
				bw.write(String.format("		select * from (select  * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		) where ROWNUM=1");
				bw.newLine();
			}
			else if(dbType == DBType.DB2){
				bw.write(String.format("		select * from (select *,ROW_NUMBER OVER() as row_index from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		) where row_index = 1");
				bw.newLine();
			}
			else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
				bw.write(String.format("		select * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		limit 1");
				bw.newLine();
			}
			bw.write("	</select>");
			bw.newLine();
			//selectList
			bw.write("	<!-- selectList -->");
			bw.newLine();
			bw.write("	<select id=\"selectList\" parameterType=\"java.util.Map\" resultMap=\"resultMap\">");
			bw.newLine();
			if(dbType == DBType.MSSQL){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.ORACLE){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.DB2){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
				bw.write(String.format("		select * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit\" />");
				bw.newLine();
			}
			bw.write("	</select>");
			bw.newLine();

			//selectPageList
			bw.write("	<!-- selectPageList -->");
			bw.newLine();
			bw.write("	<select id=\"selectPageList\" parameterType=\"java.util.Map\" resultMap=\"resultMap\">");
			bw.newLine();
			if(dbType == DBType.MSSQL){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.ORACLE){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.DB2){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
				bw.write(String.format("		select * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit\" />");
				bw.newLine();
			}
			bw.write("	</select>");
			bw.newLine();

			//selectMap
			bw.write("	<!-- selectMap -->");
			bw.newLine();
			bw.write("	<select id=\"selectMap\" parameterType=\"java.util.Map\" resultMap=\"resultMap\">");
			bw.newLine();
			if(dbType == DBType.MSSQL){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.ORACLE){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.DB2){
				bw.write("		<include refid=\"limit_header\"/>");
				bw.newLine();
				bw.write("		select ");
				bw.newLine();
				bw.write("		<include refid=\"limit_rownumber\"/>");
				bw.newLine();
				bw.write(String.format("		* from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit_footer\"/>");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
			}
			else if(dbType == DBType.MySQL || dbType == DBType.PGSQL){
				bw.write(String.format("		select * from %s ", table));
				bw.newLine();
				bw.write("		<include refid=\"where\" />");
				bw.newLine();
				bw.write("		<include refid=\"order_by\" />");
				bw.newLine();
				bw.write("		<include refid=\"limit\" />");
				bw.newLine();
			}
			bw.write("	</select>");
			bw.newLine();

			//selectAll
			bw.write("	<!-- selectAll -->");
			bw.newLine();
			bw.write("	<select id=\"selectAll\" resultMap=\"resultMap\">");
			bw.newLine();
			bw.write(String.format("		select * from %s", table));
			bw.newLine();
			bw.write("	</select>");
			bw.newLine();
		}
		catch(Exception e){
			logger.error("buildMapper.Select.Exception="+e.getMessage());
		}
	}

	/**
	 * buildMapperInsert
	 * @param bw
	 * @param table
	 * @param columns
	 */
	private void buildMapperInsert(BufferedWriter bw, String table, List<TableColumn> columns, String entityPackageName){
		try{
			bw.write("	<!-- insert -->");
			bw.newLine();
			bw.write("	<insert id=\"insert\" parameterType=\"java.util.Map\">");
			bw.newLine();
			String fields = "";
			String values = "";
			TableColumn autoIncrementKeyColumn = null;
			for (TableColumn item : columns) {
				//自增字段跳过
				if(item.getIsAutoIncrement()){
					//自增主键
					if(item.getIsKey() && item.getIsAutoIncrement())
						autoIncrementKeyColumn = item;
					continue;
				}
				fields += String.format(",%s", item.getColumnName());
				values += String.format(",#{%s}", item.getPropertyName());
			}
			if(!StringUtils.isEmpty(fields) && fields.startsWith(",")){
				fields = fields.substring(1);
			}
			if(!StringUtils.isEmpty(values) && values.startsWith(",")){
				values = values.substring(1);
			}
			bw.write(String.format("		insert into %s ", table));
			bw.newLine();
			bw.write(String.format("		(%s) ", fields));
			bw.newLine();
			bw.write(String.format("		values "));
			bw.newLine();
			bw.write(String.format("		(%s)", values));
			bw.newLine();

			bw.write("	</insert>");
			bw.newLine();
			//如果有自增主键
			if(autoIncrementKeyColumn != null){
				//useGeneratedKeys="true" keyColumn="staff_id" keyProperty="staffId"
				bw.write(String.format("	<insert id=\"insertAndGetAutoIncrementId\" parameterType=\"%s\" useGeneratedKeys=\"true\" keyColumn=\"%s\" keyProperty=\"%s\">", entityPackageName, autoIncrementKeyColumn.getColumnName(), autoIncrementKeyColumn.getPropertyName()));
				bw.newLine();
				bw.write(String.format("		insert into %s ", table));
				bw.newLine();
				bw.write(String.format("		(%s) ", fields));
				bw.newLine();
				bw.write(String.format("		values "));
				bw.newLine();
				bw.write(String.format("		(%s)", values));
				bw.newLine();

				bw.write("	</insert>");
				bw.newLine();
			}
		}
		catch(Exception e){
			logger.error("buildMapper.Insert.Exception="+e.getMessage());
		}
	}

	/**
	 * buildMapperUpdate
	 * @param bw
	 * @param table
	 * @param columns
	 */
	private void buildMapperUpdate(BufferedWriter bw, String table, List<TableColumn> columns){
		try{

			bw.write("	<!-- update -->");
			bw.newLine();
			bw.write("	<update id=\"update\" parameterType=\"java.util.Map\">");
			bw.newLine();
			bw.write(String.format("		update %s set ", table));
			bw.newLine();
			bw.write("		<trim prefixOverrides=\",\">");
			bw.newLine();
			TableColumn keyColumn = null;
			for (TableColumn item : columns) {
				if(item.getIsKey()){
					keyColumn = item;
					continue;
				}
				// boolean
				if (item.getDataType() == TableColumnDataType.BIT
						|| item.getDataType() == TableColumnDataType.BOOLEAN
						|| item.getDataType() == TableColumnDataType.TINYINT) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s=#{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// int
				else if (item.getDataType() == TableColumnDataType.SMALLINT) {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}

				}// long
				else if (item.getDataType() == TableColumnDataType.INTEGER
						|| item.getDataType() == TableColumnDataType.BIGINT) {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}


				}// double
				else if (item.getDataType() == TableColumnDataType.DOUBLE
						|| item.getDataType() == TableColumnDataType.FLOAT) {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}


				}// float
				else if (item.getDataType() == TableColumnDataType.REAL) {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}


				}// byte[]
				else if (item.getDataType() == TableColumnDataType.BINARY
						|| item.getDataType() == TableColumnDataType.VARBINARY
						|| item.getDataType() == TableColumnDataType.LONGVARBINARY
						|| item.getDataType() == TableColumnDataType.BLOB) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// BigDecimal
				else if (item.getDataType() == TableColumnDataType.NUMERIC
						|| item.getDataType() == TableColumnDataType.DECIMAL) {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}


				}// Date
				else if (item.getDataType() == TableColumnDataType.DATE) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// time
				else if (item.getDataType() == TableColumnDataType.TIME) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// Timestamp
				else if (item.getDataType() == TableColumnDataType.TIMESTAMP) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// Object
				else if (item.getDataType() == TableColumnDataType.OTHER
						|| item.getDataType() == TableColumnDataType.NULL) {
					bw.write(String.format(
							"			<if test=\"%s != null \">, %s = #{%s}</if>",
							item.getPropertyName(), item.getColumnName(),
							item.getPropertyName()));

				}// String
				else {
					if(!item.getIsNullable()){
						bw.write(String
								.format("			<if test=\"%s != null and %s != '' \">,%s = #{%s}</if>",
										item.getPropertyName(),
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}
					else{
						bw.write(String
								.format("			<if test=\"%s != null \">,%s = #{%s}</if>",
										item.getPropertyName(),
										item.getColumnName(),
										item.getPropertyName()));
					}

				}
				bw.newLine();
			}
			bw.write("		</trim>");
			bw.newLine();
			bw.write("		<include refid=\"where\"/>");
			bw.newLine();
			bw.write("	</update>");
			bw.newLine();
			//如果有主键列则创建updateByKey
			if(keyColumn != null){
				//updateByKey
				bw.write("	<!-- updateByKey -->");
				bw.newLine();
				bw.write("	<update id=\"updateByKey\" parameterType=\"java.util.Map\">");
				bw.newLine();
				bw.write(String.format("		update %s set ", table));
				bw.newLine();
				bw.write("		<trim prefixOverrides=\",\">");
				bw.newLine();
				for (TableColumn item : columns) {
					if(item.getIsKey()){
						continue;
					}
					// boolean
					if (item.getDataType() == TableColumnDataType.BIT
							|| item.getDataType() == TableColumnDataType.BOOLEAN
							|| item.getDataType() == TableColumnDataType.TINYINT) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s=#{%s}</if>",
								item.getPropertyName(), item.getColumnName(),
								item.getPropertyName()));

					}// int
					else if (item.getDataType() == TableColumnDataType.SMALLINT) {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}

					}// long
					else if (item.getDataType() == TableColumnDataType.INTEGER
							|| item.getDataType() == TableColumnDataType.BIGINT) {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}


					}// double
					else if (item.getDataType() == TableColumnDataType.DOUBLE
							|| item.getDataType() == TableColumnDataType.FLOAT) {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}


					}// float
					else if (item.getDataType() == TableColumnDataType.REAL) {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}


					}// byte[]
					else if (item.getDataType() == TableColumnDataType.BINARY
							|| item.getDataType() == TableColumnDataType.VARBINARY
							|| item.getDataType() == TableColumnDataType.LONGVARBINARY
							|| item.getDataType() == TableColumnDataType.BLOB) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s = #{%s}</if>",
								item.getPropertyName(), item.getColumnName(),
								item.getPropertyName()));

					}// BigDecimal
					else if (item.getDataType() == TableColumnDataType.NUMERIC
							|| item.getDataType() == TableColumnDataType.DECIMAL) {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s > 0 \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">, %s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}


					}// Date
					else if (item.getDataType() == TableColumnDataType.DATE) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s = #{%s}</if>",
								item.getPropertyName(), item.getColumnName(),
								item.getPropertyName()));

					}// time
					else if (item.getDataType() == TableColumnDataType.TIME) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s = #{%s}</if>",
								item.getPropertyName(), item.getColumnName(),
								item.getPropertyName()));

					}// Timestamp
					else if (item.getDataType() == TableColumnDataType.TIMESTAMP) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s = #{%s}</if>",
								item.getPropertyName(),
								item.getColumnName(),
								item.getPropertyName()));

					}// Object
					else if (item.getDataType() == TableColumnDataType.OTHER
							|| item.getDataType() == TableColumnDataType.NULL) {
						bw.write(String.format(
								"			<if test=\"%s != null \">, %s = #{%s}</if>",
								item.getPropertyName(),
								item.getColumnName(),
								item.getPropertyName()));

					}// String
					else {
						if(!item.getIsNullable()){
							bw.write(String
									.format("			<if test=\"%s != null and %s != '' \">,%s = #{%s}</if>",
											item.getPropertyName(),
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}
						else{
							bw.write(String
									.format("			<if test=\"%s != null \">,%s = #{%s}</if>",
											item.getPropertyName(),
											item.getColumnName(),
											item.getPropertyName()));
						}

					}
					bw.newLine();
				}
				bw.write("		</trim>");
				bw.newLine();
				bw.write(String.format("		where %s = #{%s}", keyColumn.getColumnName(), keyColumn.getPropertyName()));
				bw.newLine();
				bw.write("	</update>");
				bw.newLine();
			}

		}
		catch(Exception e){
			logger.error("buildMapper.Update.Exception="+e.getMessage());
		}
	}

	/**
	 * buildMapperDelete
	 * @param bw
	 * @param table
	 * @param column
	 */
	private void buildMapperDelete(BufferedWriter bw, String table, TableColumn keyColumn){
		try{
			bw.write("	<!-- delete -->");
			bw.newLine();
			bw.write("	<delete id=\"delete\" parameterType=\"java.util.Map\">");
			bw.newLine();
			bw.write(String.format("		delete from %s ", table));
			bw.newLine();
			bw.write("		<include refid=\"where\"/>");
			bw.newLine();
			bw.write("	</delete>");
			bw.newLine();
			if(keyColumn != null){
				bw.write("	<!-- deleteByKey -->");
				bw.newLine();
				bw.write("	<delete id=\"deleteByKey\" parameterType=\"java.util.Map\">");
				bw.newLine();
				bw.write(String.format("		delete from %s where %s = #{%s}", table, keyColumn.getColumnName(), keyColumn.getPropertyName()));
				bw.newLine();
				bw.write("	</delete>");
				bw.newLine();
			}
			bw.newLine();
		}
		catch(Exception e){
			logger.error("buildMapper.Delete.Exception="+e.getMessage());
		}
	}

	/**
	 * 字符串首字母转化为大写字母
	 * @param input
	 * @return
	 */
	protected String firstLetterToUpper(String input){
		if(StringUtils.isBlank(input))
			return "";
		return input.substring(0, 1).toUpperCase() + input.substring(1);
	}
	/**
	 * 首字母转化成小写字母
	 * @param input
	 * @return
	 */
	protected String firstLetterToLower(String input){
		if(StringUtils.isBlank(input))
			return "";
		return input.substring(0, 1).toLowerCase() + input.substring(1);
	}

	/**
	 * 下划线转驼峰
	 *
	 * @param input
	 * @return
	 */
	protected String underlineToCamel(String input) {
		if (StringUtils.isBlank(input)) {
			return "";
		}
		int len = input.length();
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			char c = input.charAt(i);
			if (c == '_') {
				if (++i < len) {
					sb.append(Character.toUpperCase(input.charAt(i)));
				}
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}

	/**
	 * 创建文件夹
	 * @param folder
	 * @return
	 */
	private Boolean createDir(String folder){
		if(StringUtils.isBlank(folder))
			return false;
		if(!folder.endsWith("/")){
			folder += "/";
		}
		try{
			File dir = new File(folder);
			if(dir.exists()){
				return true;
			}
			return dir.mkdirs();
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		return false;
	}

	/**
	 * 创建文件
	 * @param fileName
	 * @return
	 */
	private Boolean createFile(String fileName){
		if(StringUtils.isBlank(fileName))
			return false;
		try{
			String dir = fileName.substring(0, fileName.lastIndexOf("/"));
			if(createDir(dir)){
				File file = new File(fileName);
				if(file.exists()){
					return true;
				}
				return file.createNewFile();
			}
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		return false;
	}

	/**
	 * 获取BufferedWriter
	 * @param fileName
	 * @return
	 */
	private BufferedWriter getBufferedWriter(String fileName){
		if(StringUtils.isBlank(fileName))
			return null;
		fileName = fileName.replace("//", "/");
		File file = new File(fileName);
		Boolean exist = false;
		if(!file.exists()){
			exist = createFile(fileName);
		}
		else{
			exist = true;
		}
		if(!exist) return null;
		try{
			return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8"));
		}
		catch(Exception e){

		}
		return null;
	}

	/**
	 * 数据库类型
	 * @author mqy
	 *
	 */
	protected enum DBType{
		DB2("db2"),
		MSSQL("mssql"),
		MySQL("mysql"),
		ORACLE("orcale"),
		PGSQL("postgresql")
		;
		private DBType(String name){
			this.name = name;
		}
		private String   name;
		public String getName() {
			return name;
		}
	}
}
